/*-
 * Copyright (c) 2009-2010 Shang-Rong Cai. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $ Bitmap: method_8.c    Rev. 0.9.1    2010-10-20T09:17+08:00 $
 */

#ifdef TRACE_INFO
#include <stdio.h>
#endif

#include <bscerr.h>
#include <bitmap.h>


/* For Width Block (64 Bits) */
#define OCTO_BLOCK (size_t) 8

#define BITMAP_8_BYTES_NONE (uint64_t) 0x0000000000000000
#define BITMAP_8_BYTES_MARK (uint64_t) 0xffffffffffffffff


int bitmap_all_mark(bitmap_t *bm)
{
    int ierr = ERRNO_NO_ERROR;
    size_t zi;  /* size_t based loop counter or index */

    size_t obsz;
    uint64_t *optr;

#ifdef TRACE_INFO
    printf("[F] bitmap_all_mark()\n");
#endif

    obsz = bm->bksz / OCTO_BLOCK;

    optr = (uint64_t*) bm->list;

    for (zi = 0; zi < obsz; zi++)
    {
        optr[zi] = BITMAP_8_BYTES_MARK;
    }

    for (zi = obsz * OCTO_BLOCK; zi < bm->bksz; zi++)
    {
        bm->list[zi] = BITMAP_ALL_MARK;
    }

#ifdef TRACE_INFO
    printf("    bitmap_all_mark() Passed!\n");
#endif

    return ierr;
}


int bitmap_all_none(bitmap_t *bm)
{
    int ierr = ERRNO_NO_ERROR;
    size_t zi;  /* size_t based loop counter or index */

    size_t obsz;
    uint64_t *optr;

#ifdef TRACE_INFO
    printf("[F] bitmap_all_none()\n");
#endif

    obsz = bm->bksz / OCTO_BLOCK;

    optr = (uint64_t*) bm->list;

    for (zi = 0; zi < obsz; zi++)
    {
        optr[zi] = BITMAP_8_BYTES_NONE;
    }

    for (zi = obsz * OCTO_BLOCK; zi < bm->bksz; zi++)
    {
        bm->list[zi] = BITMAP_ALL_NONE;
    }

#ifdef TRACE_INFO
    printf("    bitmap_all_none() Passed!\n");
#endif

    return ierr;
}


size_t count_marks_uint64_t(uint64_t bbk)
{
    size_t cnt = 0;
    uint64_t tmp;

    while (bbk != BITMAP_8_BYTES_NONE)
    {
        cnt++;
        tmp = bbk - (uint64_t) 0x0000000000000001;
        bbk &= tmp;
    }

    return cnt;
}

int bitmap_count_marks(bitmap_t *bm, size_t *mks)
{
    int ierr = ERRNO_NO_ERROR;
    size_t zi;  /* size_t based loop counter or index */
    size_t srsz;  /* Shift to right size */

    uint8_t bbk;
/*
    uint16_t bbk;
    uint16_t *ptr
*/
/*
    uint32_t bbk;
*/
/*
    uint64_t bbk;
*/

#ifdef TRACE_INFO
    printf("[F] bitmap_count_marks()\n");
#endif

    *mks = 0;

    /* 8 Bits Per Round */
    srsz = BITMAP_BLOCK_SIZE - (bm->size % BITMAP_BLOCK_SIZE);

    if (srsz == BITMAP_BLOCK_SIZE)
    {
        for (zi = 0; zi < bm->bksz; zi++)
        {
            (*mks) += count_marks_uint8_t(bm->list[zi]);
        }
    }
    else
    {
        for (zi = 0; zi < bm->bksz - 1; zi++)
        {
            (*mks) += count_marks_uint8_t(bm->list[zi]);
        }

        bbk = bm->list[bm->bksz - 1];
        bbk >>= srsz;

        (*mks) += count_marks_uint8_t(bbk);
    }

    /* 16 Bits Per Round */
/*
    srsz = BITMAP_BLOCK_SIZE * DUAL_BLOCK - (bm->size % (BITMAP_BLOCK_SIZE * DUAL_BLOCK));
    ptr = (uint16_t*) bm->list;

    if (srsz == (BITMAP_BLOCK_SIZE * DUAL_BLOCK))
    {
        for (zi = 0; zi < bm->bksz / DUAL_BLOCK; zi++)
        {
            (*mks) += count_marks_uint16_t(ptr[zi]);
        }
    }
    else
    {
        for (zi = 0; zi < bm->bksz / DUAL_BLOCK - 1; zi++)
        {
            (*mks) += count_marks_uint16_t(ptr[zi]);
        }

        if (bm->bksz % 2 == 0)
        {
            bbk = bm->list[bm->bksz / DUAL_BLOCK - 1];
            bbk >>= srsz;
        }
        else
        {
            bbk = bm->list[bm->bksz - 1];
            bbk >>= (srsz - BITMAP_BLOCK_SIZE);
        }

        (*mks) += count_marks_uint16_t(bbk);
    }
*/

    /* 32 Bits Per Round */
/*
    srsz = BITMAP_BLOCK_SIZE * QUAD_BLOCK - (bm->size % (BITMAP_BLOCK_SIZE * QUAD_BLOCK));

    if (srsz == (BITMAP_BLOCK_SIZE * QUAD_BLOCK))
    {
        for (zi = 0; zi < bm->bksz; zi++)
        {
            (*mks) += count_marks_uint32_t(bm->list[zi]);
        }
    }
    else
    {
        for (zi = 0; zi < bm->bksz - 1; zi++)
        {
            (*mks) += count_marks_uint32_t(bm->list[zi]);
        }

        bbk = bm->list[bm->bksz - 1];
        bbk >>= srsz;

        (*mks) += count_marks_uint32_t(bbk);
    }
*/
    /* 64 Bits Per Round */
/*
    srsz = BITMAP_BLOCK_SIZE * OCTO_BLOCK - (bm->size % (BITMAP_BLOCK_SIZE * OCTO_BLOCK));

    if (srsz == (BITMAP_BLOCK_SIZE * OCTO_BLOCK))
    {
        for (zi = 0; zi < bm->bksz; zi++)
        {
            (*mks) += count_marks_uint64_t(bm->list[zi]);
        }
    }
    else
    {
        for (zi = 0; zi < bm->bksz - 1; zi++)
        {
            (*mks) += count_marks_uint64_t(bm->list[zi]);
        }

        bbk = bm->list[bm->bksz - 1];
        bbk >>= srsz;

        (*mks) += count_marks_uint64_t(bbk);
    }
*/

#ifdef TRACE_INFO
    printf("    bitmap_count_marks() Passed!\n");
#endif

    return ierr;
}


size_t count_nones_uint8_t(uint8_t bbk)
{
    size_t cnt = 0;
    uint8_t tmp;

    while (bbk != BITMAP_ALL_MARK)
    {
        cnt++;
        tmp = bbk + (uint8_t) 0x01;
        bbk |= tmp;
    }

    return cnt;
}


size_t count_nones_uint16_t(uint16_t bbk)
{
    size_t cnt = 0;
    uint16_t tmp;

    while (bbk != BITMAP_2_BYTES_MARK)
    {
        cnt++;
        tmp = bbk + (uint16_t) 0x0001;
        bbk |= tmp;
    }

    return cnt;
}


size_t count_nones_uint32_t(uint32_t bbk)
{
    size_t cnt = 0;
    uint16_t tmp;

    while (bbk != BITMAP_4_BYTES_MARK)
    {
        cnt++;
        tmp = bbk + (uint32_t) 0x00000001;
        bbk |= tmp;
    }

    return cnt;
}


size_t count_nones_uint64_t(uint64_t bbk)
{
    size_t cnt = 0;
    uint16_t tmp;

    while (bbk != BITMAP_8_BYTES_MARK)
    {
        cnt++;
        tmp = bbk + (uint64_t) 0x0000000000000001;
        bbk |= tmp;
    }

    return cnt;
}


int bitmap_count_nones(bitmap_t *bm, size_t *nns)
{
    int ierr = ERRNO_NO_ERROR;

    size_t zi;  /* size_t based loop counter or index */
    size_t srsz;  /* Shift to right size */

    uint8_t bbk;

#ifdef TRACE_INFO
    printf("[F] bitmap_count_nones()\n");
#endif

    *nns = 0;

    /* 8 Bits Per Round */
    srsz = bm->size % BITMAP_BLOCK_SIZE;

    if (srsz == 0)
    {
        for (zi = 0; zi < bm->bksz; zi++)
        {
            (*nns) += count_nones_uint8_t(bm->list[zi]);
        }
    }
    else
    {
        for (zi = 0; zi < bm->bksz - 1; zi++)
        {
            (*nns) += count_nones_uint8_t(bm->list[zi]);
        }

        bbk = BITMAP_ALL_MARK;
        bbk >>= srsz;
        bbk |= bm->list[bm->bksz - 1];

        (*nns) += count_nones_uint8_t(bbk);
    }

    /* 16 Bits Per Round */

    /* 32 Bits Per Round */

    /* 64 Bits Per Round */

#ifdef TRACE_INFO
    printf("    bitmap_count_nones() Passed!\n");
#endif

    return ierr;
}

